"""
"""
import os, sys

parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 4)))
sys.path.insert(0, parent_path)

from typing import *
import cv2, time, traceback
from queue import Queue
import threading
from core.utils.logger import logging


class VideoReader(object):
    def __init__(self, mode="block", buffer_size = 2, retry_time = 5):
        assert mode in ["block","real_time"], "|ERR: VideoReader mode should in [block, real_time]|"
        self.mode = mode
        self.buffer = Queue(maxsize=buffer_size)
        self.last_frame = None
        self.cap = None
        self.status = 0 # 0: standby/done 1: ready 2: running
        self.run_thread = None
        self.max_retry = retry_time
    
    # 初始化Capture
    def init_cap(self,file_path):
        try:
            self.file_path = file_path
            capture = cv2.VideoCapture(file_path)
            self.cap = capture
            # 获取参数
            self.width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
            self.height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.fps = int(capture.get(cv2.CAP_PROP_FPS))
            self.frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
            ret, frame = self.cap.read()
            self.last_frame = frame
            assert ret, logging.error("|ERR: init cap fail, reading fail.|")
            # 清空buffer
            self.buffer.queue.clear()
            # 声明run进程
            self.run_thread = threading.Thread(target=self.run)
            # 变更状态机
            self.status = 1 # ready
            return True
        except:
            logging.error(traceback.format_exc())
            return False

    def read(self):
        ret = False
        data = None
        if not self.is_running():
            return ret, data
        try:
            data = self.buffer.get_nowait() if self.mode == "real_time" else self.buffer.get(timeout=5)
            self.last_frame = data
            ret = True
        except:
            if self.mode == "real_time":
                data = self.last_frame
            else:
                ret = False
        finally:
            return ret, data

    def start(self):
        self.run_thread.start()
        time.sleep(0.1) # 等待主循环进入
        
    def run(self):
        try:
            retry_time = 0
            self.status = 2
            while self.status==2:
                ret, frame = self.cap.read()
                # 读取失败, 尝试重连
                if not ret:
                    retry_time+=1
                    # 达到最大重试次数, 执行close切换为standby状态并退出循环
                    if retry_time > self.max_retry:
                            logging.error("|ERR: cap retry more than {}, close this cap|".format(retry_time))
                            break
                    # 等待后尝试重连
                    time.sleep(2)
                    logging.warning(f"|WAR: cap reading fail, waiting 2s and retry {retry_time}|")
                    self.cap = cv2.VideoCapture(self.file_path)
                    continue
                else:
                    retry_time = 0
                
                if self.mode == "real_time":
                    try:
                        self.buffer.put_nowait(frame)
                    except:
                        pass
                else:
                    self.buffer.put(frame)
                time.sleep(1/1000) # reader不控制读取间隔, 应由外部控制
        except:
            logging.error(traceback.format_exc())
        finally:
            self.close()
            self.cap.release()

    def is_running(self):
        return self.status==2

    def get_status(self):
        return self.status

    def close(self):
        self.status = 0

if __name__ == "__main__":
    video_reader = VideoReader()
    if video_reader.init_cap("data/input/car_test_video.mp4"): 
        video_reader.start()


    while 1:
        ret, frame = video_reader.read()
        cv2.imwrite("temp.jpg",frame)
        time.sleep(1)